﻿package com.flashdynamix.motion.extras {	/**	 * Has methods that provide enhancements to assist with applying ColorMatrixFilter effects to DisplayObjects.<BR>	 * These methods include :<BR>	 * <ul>	 * <li>brightness</li>	 * <li>saturation</li>	 * <li>hue</li>	 * <li>threshold</li>	 * <li>colorize</li>	 * <li>contrast</li>	 * </ul>	 */	public dynamic class ColorMatrix extends Array {
		public static const identity : Array = [1,0,0,0,0,										   		0,1,0,0,0,										   		0,0,1,0,0,										   		0,0,0,1,0];		private static const LUMA_R : Number = 0.212671;		private static const LUMA_G : Number = 0.715160;		private static const LUMA_B : Number = 0.072169;		private var _colorize : Number;		private var _colorizeAmount : Number = 1;
		private var _brightness : Number = 0;		private var _threshold : Number = 0;		private var _hueRotation : Number = 0;		private var _saturation : Number = 0;		private var _contrast : Number = 0;		private var degreeRad : Number = Math.PI / 180;
		/**		 * Constructs an instance of ColorMatrix.		 * @param matrix The current matrix used by the ColorMatrixFilter.		 */		public function ColorMatrix(brightness : Number = 0, saturation : Number = 1, contrast : Number = 1, hueRotation : Number = 0, threshold : Number = -1, colorize : int = -1, colorizeAmount : Number = -1) {			var i : int = 0;			var x : int;			var y : int;			for (y = 0;y < 4; y++) {				for (x = 0;x < 5; x++) {					this[i] = identity[i];					i++;				}			}						if(colorize >= 0) this.colorize = colorize;			if(colorizeAmount >= 0) this.colorizeAmount = colorizeAmount;			this.brightness = brightness;			this.saturation = saturation;			this.contrast = contrast;			this.hueRotation = hueRotation;			if(threshold >= 0) this.threshold = threshold;		}
		public function set colorize(color : uint) : void {			_colorize = color;			applyColorize(_colorize, _colorizeAmount);		}
		/**		Sets and returns a hexadecimal number e.g. 0xFFFFFF will turn the picture into grayscale.		 */		public function get colorize() : uint {			return _colorize;		} 
		public function set colorizeAmount(amount : Number) : void {			_colorizeAmount = amount;			if(!isNaN(colorize)) applyColorize(_colorize, _colorizeAmount);		}
		/**		Sets and returns the amount of this color to apply from 0 to 1.		 */		public function get colorizeAmount() : Number {			return _colorizeAmount;		}
		public function set brightness(amount : Number) : void {			_brightness = amount;			applyBrightness(_brightness);		}
		/**		 * Sets and returns a brightness amount from -1 to 1.		 */		public function get brightness() : Number {			return _brightness;		}
		public function set threshold(amount : Number) : void {			_threshold = amount;			applyThreshold(_threshold);		}
		/**		 * Sets and returns the amount of threshold to apply from 0 to 256.		 */		public function get threshold() : Number {			return _threshold;		}
		public function set hueRotation(degree : Number) : void {			_hueRotation = degree;			applyHueRotation(_hueRotation);		}
		/**		 * Sets and returns the amount in degrees to rotate the hueRotation from -360 to 360.		 */		public function get hueRotation() : Number {			return _hueRotation;		}		public function set saturation(amount : Number) : void {			_saturation = amount;			applySaturation(_saturation);		}		/**		 * Sets and returns the amount of saturation offset from 0 (grayscale) to 1 (normal) to 10 (highly saturated).		 */		public function get saturation() : Number {			return _saturation;		}		public function set contrast(amount : Number) : void {			_contrast = amount;			applyContrast(_contrast);		}		/**		 * Sets and returns the amount of contrast offset from 0 (gray) to 1 (normal) to 10 (high contrast).		 */		public function get contrast() : Number {			return _contrast;		}
		private function applyColorize(color : uint, amount : Number = 1) : void {			var r : Number = ((color >> 16) & 0xFF) / 255;			var g : Number = ((color >> 8) & 0xFF) / 255;			var b : Number = (color & 0xFF) / 255;			var q : Number = 1 - amount;						var rA : Number = amount * r;			var gA : Number = amount * g;			var bA : Number = amount * b;						var trans : Array = [q + rA * LUMA_R, rA * LUMA_G, rA * LUMA_B, 0, 0,							  	 gA * LUMA_R, q + gA * LUMA_G, gA * LUMA_B, 0, 0,							  	 bA * LUMA_R, bA * LUMA_G, q + bA * LUMA_B, 0, 0,							  	 0, 0, 0, 1, 0];					apply(trans);		}
		private function applyThreshold(amount : Number) : void {			var trans : Array = [LUMA_R * 256, LUMA_G * 256, LUMA_B * 256, 0,  -256 * amount, 								 LUMA_R * 256, LUMA_G * 256, LUMA_B * 256, 0,  -256 * amount, 								 LUMA_R * 256, LUMA_G * 256, LUMA_B * 256, 0,  -256 * amount, 								 0, 0, 0, 1, 0];			apply(trans);		}
		private function applyHueRotation(degree : Number) : void {			var rads : Number = degree * degreeRad;						var cos : Number = Math.cos(rads);			var sin : Number = Math.sin(rads);						var trans : Array = [((LUMA_R + (cos * (1 - LUMA_R))) + (sin * -(LUMA_R))), ((LUMA_G + (cos * -(LUMA_G))) + (sin * -(LUMA_G))), ((LUMA_B + (cos * -(LUMA_B))) + (sin * (1 - LUMA_B))), 0, 0,             					((LUMA_R + (cos * -(LUMA_R))) + (sin * 0.143)), ((LUMA_G + (cos * (1 - LUMA_G))) + (sin * 0.14)), ((LUMA_B + (cos * -(LUMA_B))) + (sin * -0.283)), 0, 0,             					((LUMA_R + (cos * -(LUMA_R))) + (sin * -((1 - LUMA_R)))), ((LUMA_G + (cos * -(LUMA_G))) + (sin * LUMA_G)), ((LUMA_B + (cos * (1 - LUMA_B))) + (sin * LUMA_B)), 0, 0,             					0, 0, 0, 1, 0];			apply(trans);		}
		private function applyBrightness(offset : Number) : void {			offset = ((offset + 1) * 255) - 255;						var trans : Array = [1,0,0,0,offset,								 0,1,0,0,offset,								 0,0,1,0,offset,								 0,0,0,1,0,								 0,0,0,0,1];			apply(trans);		}
		private function applySaturation(offset : Number) : void {			var q : Number = 1 - offset;			var r : Number = q * LUMA_R;			var g : Number = q * LUMA_G;			var b : Number = q * LUMA_B;						var trans : Array = [r + offset, g , b , 0, 0,							  	 r, g + offset, b, 0, 0,							  	 r, g, b + offset, 0, 0,							  	 0, 0, 0, 1, 0];			apply(trans);		}
		private function applyContrast(offset : Number) : void {			var q : Number = 1 - offset;						var trans : Array = [offset,0,0,0,128 * q,							   	 0,offset,0,0,128 * q,							   	 0,0,offset,0,128 * q,							   	 0,0,0,1,0];			apply(trans);		}
		/**		 * Reverts the ColorMatrix back to it's initial setting undoing all effects applied.		 */		public function revert() : void {			var i : int = 0;			var x : int;			var y : int;			for (y = 0;y < 4; y++) {				for (x = 0;x < 5; x++) {					this[i] = identity[i];					i++;				}			}		}
		private function apply(mtx : Array) : void {			var trans : Array = [];			var i : int = 0;			var x : int;			var y : int;			var z : int = 0;						for (y = 0;y < 4; y++) {				for (x = 0;x < 5; x++) {					if (x == 4) {						z = mtx[i + 4];					} else {						z = 0;					}					trans[i + x] = mtx[i] * this[x] + mtx[i + 1] * this[x + 5] + mtx[i + 2] * this[x + 10] + mtx[i + 3] * this[x + 15] + z;				}				i += 5;			}						i = 0;			for (y = 0;y < 4; y++) {				for (x = 0;x < 5; x++) {					this[i] = trans[i];					i++;				}			}		}	}}